package edu.cmu.cs211.snake.gui;

import java.awt.Dimension;
import java.awt.Point;
import java.util.Collections;
import java.util.Queue;
import java.util.Set;

import edu.cmu.cs211.snake.util.ArrayQueue;
import edu.cmu.cs211.snake.util.MyHashSet;

public class Snake {

	private Queue <Point> points = new ArrayQueue <Point> ();

	private Set <Point> ptshash = new MyHashSet <Point> ();

	// a vector representing our next move. must have
	// mag. of one and be made of integers
	private Dimension direction = new Dimension (1, 0);

	private Point head = new Point (0, 0);
	
	private Point nextHead = head;

	private int growthNeeded;

	public Snake () {
		reinit();
	}

	private void add (Point p)
	{
		ptshash.add (p);
		points.add (p);
	}

	private void remove ()
	{
		if (points.size () > 0)
			ptshash.remove (points.poll ());
	}

	public Set<Point> getPoints ()
	{
		return Collections.unmodifiableSet (ptshash);
	}

	public Point getNextHead ()
	{
		return new Point (head.x + direction.width, head.y + direction.height);
	}

	public void growBy (int n)
	{
		growthNeeded += n;
	}

	private void setDirection (Dimension d)
	{
		// Don't allow reversing of directions
		if (d.height == -direction.height && d.width == -direction.width)
			return;
		direction = d;
	}

	public void moveTo (Point p)
	{
		if (growthNeeded > 0)
			--growthNeeded;
		else
			remove ();

		add (head = p);
	}

	public void right() {
	    setDirection (new Dimension (1, 0));
	}
	
	public void left() {
	    setDirection (new Dimension (-1, 0));
	}
	
	public void up() {
	    setDirection (new Dimension (0, -1));
	}
	
	public void down() {
	    setDirection (new Dimension (0, 1));
	}
	
	public Point startTick() {
	    nextHead = getNextHead();
	    return nextHead;
	}
	
	public void endTick() {
	    moveTo (nextHead);
	}
	
	public void reinit() {
	    moveTo(new Point(0,0));
	    right();
	}
}
